1. Field of the Invention
The present invention relates primarily to the field of dynamically typed programming languages, and in particular to a method and apparatus for implementation of an input/output (I/O) stream operator in a dynamically typed programming language.
Portions of the disclosure of this patent document contain material that is subject to copyright protection. The copyright owner has no objection to the facsimile reproduction by anyone of the patent document or the patent disclosure as it appears in the Patent and Trademark Office file or records, but otherwise reserves all rights whatsoever.
2. Background Art
Prior art programming languages, especially object-oriented languages like C, C++, and JAVA, to name a few, have an I/O facility that has to be imported (streamed) via special libraries. The I/O character is not built into the language, but is part of a stream operator, which is part of the special library, that allows the contents of one value to be copied to another.
Since the library includes other operators and functions, it constitutes unnecessarily huge overhead, especially if only a few of the operators and functions are used by the program. This overhead may make a program bulky to transport since the overall size of the program increases because of this overhead. Furthermore, this overhead may make a program slow to run because the program has to access the stream operator in the special library whenever it needs certain tasks like accepting user input, or displaying program output.
Streams
Streams are channels attached to an I/O port, and used for sending or receiving data. Streams may be attached to a file, screen, keyboard, network, or similar I/O devices. Standard streams, for example, stdin, stdout, and stderr, are provided for standard file descriptors available to all programs. Streams get created when a file is opened, or a network connection is made. In prior art object-oriented languages, there is a vast set of library functions available to manipulate streams.
For example, in C, a programmer has two options of storing in a variable the results of a computation. The first is by way of an assignment operation using the symbol =. The syntax for using the assignment operator is: result=expression, where the variable specified by result is assigned the value of expression. The previous value of result is destroyed. The expression can be a single variable, a single constant, or it may involve variables, constants, and arithmetic operators like +, −, *, and /. Even though the first option of using an assignment operation is powerful and used often, the user can only store the results of locally found variables and constants.
FIG. 1 illustrates the storing of a result in a variable using the first method explained above. At block 100, a result needs to be stored in a variable. At block 110, the =symbol is used to store the results. At block 120, if the expression is a single variable, then at block 130 the expression is stored in result using result=expression. At block 140, the previous value of result is lost forever. In other words, the old value of result is written over.
If at block 120, the expression is not a single variable, then at block 150 a check is made to see if the expression is a single constant. If it is, then blocks 130 and 140 are repeated. If on the other hand block 150 reveals that the expression is not a single constant, then at block 160 a check is made to see if the expression is multiple variables or constants. If it is, then blocks 130 and 140 are repeated. If on the other hand block 160 reveals that the expression is not a multiple variable or constant, then at block 170 a check is made to see if the expression involves arithmetic operators like +, −, *, or /. If it is, then blocks 130 and 140 are repeated.
If the user wants to store the results to, for example a computer monitor, or from an external source, for example a file, or wants the program to manipulate different data each time the program executes, then a second option where a function, for example, scanf in the object-oriented programming language C is used. This data transfer from the outside world into memory is called an input operation. Similarly, as a program executes, it performs computations and assigns new values to variables whose results can be displayed to the program user by an output operation using a function, for example, printf in the object oriented programming language C is used. This data transfer to the outside world from memory is called an output operation.
FIG. 2 illustrates the second option to store results to or from an external source. At block 200, if the result is to be stored from an external source, then at block 210 a function is used to transfer the data/result from the external source. If not, then a check is made at block 220 to see if different data/result needs to be manipulated. If different data/result needs to be manipulated, then block 210 is repeated. If not, then a check is made at block 230 to see if the data/result needs to be displayed to a user. If the data/result needs to be displayed, then a function is used at block 240 to display data/result to a user. If not, then the next data/result is checked at block 250, after which block 200 is repeated again.
All I/O operations, for example, in C are performed by executing special program units called I/O functions. The most common I/O functions are supplied in the C standard I/O library to which a user gains access through the use of a preprocessor directive, for example, #include<stdio.h>. The #include directives tell the preprocessor where to find the meanings of standard identifiers used in a program. These meanings are collected in files called standard header files. The header file stdio.h (the h extension defines the file as a header file) contains information about standard input and output functions such as scanf and printf.
In order to import from or write to an external source, the language offers only one solution, which is to include a library of functions. This could result in a large overhead, especially because a library contains many functions of which only a few may be used to run a program.
Similarly, in C++, a programmer has to import (or include the contents of) a header file called the iostream.h file in order to perform any I/O operations. This header file has an istream class which contain objects like cin and an ostream class which contain objects like cout. This header file is necessary to compile programs that use cin and cout. The cin object reads from standard input (keyboard, redirected file, or some similar input source), where the >> operator (also called the stream-extraction) is used for reading data. Similarly, the cout object writes to standard output (computer screen, redirected file, or some similar output source), where the << operator (also called the stream-insertion) is used for writing data.
For example, a C++ partial program is shown below to illustrate the point.
#include <iostream.h>// This preprocessor directive is the header file that has to// be imported from a C++ library.double x;// x is 8 bytes in the rough range of ±1.7976...E+308 (15 significant// digits).String s;// s is a sequence of characters.cin >> s >> x;// Input two values - one for s and another for x.cout << “s is”  << s << “, and the value of x is”  << x; // Output the value of s and x.
Here cin is the istream object attached to standard input, where the >> operator is overloaded to take an istream on the left and another type on the right. The foregoing program uses: istream :: operator >> (const char [ ])
There are other >> operators to input other data types. For example:
                int x=4;        cin>>x;        These use: istream :: operator >> (int)        
Similarly, cout is the ostream object attached to standard output. The << operator is overloaded to take an ostream on the left and another type on the right. The foregoing program uses: ostream :: operator << (const char [ ])
Just like the istream operator, there are other << operators to output other data types. For example:                int x=5;        cout<<x;        These use: ostream:: operator << (int)        
Both the stream-extraction operation (>>), and the stream-insertion operation (<<) are smart enough to know the type of data. Assuming above that x has been properly declared, no additional type information is needed.
The iostream library contains many classes for handling a wide variety of I/O operations, and include the istream class which supports stream-input operations, while the ostream class supports stream-output operations. The iostream class supports both stream-input and output operations. The iostream library also contains other objects like cerr, which is the unbuffered standard error stream, and clog, which is the buffered standard error stream. The istream and ostream classes are each derived through a single inheritance from the ios base class. The iostream class is derived through multiple inheritance from both the istream class and the ostream classes. These inheritance relationships are seen in FIG. 4A. The file processing uses the class ifstream to perform file input operations, ofstream for file output operations, and fstream for file input/output operations. Inheritance relationships between the various file processing classes are seen in FIG. 4B. Here the fstream class is derived through inheritance from the iostream class, which is derived through multiple inheritance from both the istream and ostream classes.
There are many more classes in the full stream-I/O class hierarchy supported at most installations, but the classes mentioned above provide the vast majority of needs of most programmers. Even with the few classes mentioned above, the size of this library is huge. By having to import the entire library in order to carry out any I/O operations is a big overhead, since not all operations of the I/O classes are needed for a program to run successfully.
Similarly, in JAVA, a programmer has to import a library called the java.io.* package (the .* means all files and folders under the io branch) in order to carry out any I/O operations. The reason all files and folders have to be chosen is because this package includes 8 interfaces, over 40 stream classes (excluding deprecated classes), and 16 exception classes, with an additional of 10 stream classes in the java.util.zip and java.util.jar packages, and the programmer does not know which of these classes and interfaces will be needed to run the program.
The interfaces include a data input (called DataInput) and data output (called DataOutput) interfaces. The data input interface is implemented by streams that can read primitive Java data types from a stream in a machine-independent manner. Similarly, the data output interface is implemented by streams that can write primitive Java data types to an output stream in a machine-independent manner. The DataInput interface includes about 15 methods including, readBoolean( )—reads a Boolean value from the input stream, and skipBytes(int n)—skips exactly n bytes of input, to name a couple. Similarly, the DataOutput interface includes about 14 methods including, write(byte[ ])—writes b.length bytes from the specified byte array to this output stream, and writeUTF(String)—writes a Unicode string by encoding it using modified UTF-8 format, to name a couple.
The stream classes include one for input (InputStream class) and one for output (OutputStream class), to name a couple. The abstract class InputStream is the superclass of all classes representing an input stream of bytes. Applications that need to define a subclass of InputStream must always provide a method that returns the next byte of input. This superclass includes one constructor method and 9 other methods, including, available( )—returns the number of bytes that can be read from this input stream without blocking, and read( )—reads the next byte of data from this input stream, to name a couple. This superclass is implemented by another class, called the FilterInputStream class, which has a list of methods under it. The FilterInputStream class is extended by another class called the DataInputStream class that has its own list of methods under it. FIG. 5A shows the entire hierarchical tree for the DataInputStream class described above.
Similarly, the abstract class OutputStream is the superclass of all classes representing an output stream of bytes. Applications that need to define a subclass of OutputStream must always provide at least a method that writes one byte of output. This superclass includes a constructor method and 5 other methods, including, close( )—closes this output stream and releases any stream resources associated with this stream, and write(int)—writes the specified byte to this output stream. This superclass is implemented by another class, called the FilterOutputStream class, which has a list of methods under it. The FilterOutputStream class is extended by another class called the DataOutputStream class that has its own list of methods under it. FIG. 5B shows the entire hierarchical tree for the DataOutputStream class described above.
All of these classes, sub-classes, and accompanying methods are automatically included in the java.io package, and constitute unnecessarily large overhead, especially since a program may only use a handful of these classes, sub-classes, and accompanying methods to run successfully.